package com.iwhalecloud.bss.kite.cucc.service.util;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * @author cooltan
 */
public class LocalXml2MapDom4jImpl {
    private static final boolean VALIDATE = false;

    private static final String ENCODING = "UTF-8";

    private static Log log = LogFactory.getLog(LocalXml2MapDom4jImpl.class);

    public static Document parse(String inXML) throws DocumentException {
        inXML = inXML.replaceAll("<\\?xml version=\"1.0\" encoding=\"UTF-8\"\\?>", " ");
        SAXReader saxReader = new SAXReader(VALIDATE);
        StringReader reader = new StringReader(inXML);
        Document doc = saxReader.read(reader);
        return doc;
    }

    public static String getElementStringValue(Element root, String nodeName) {
        Element el = root.element(nodeName);
        if (el != null) {
            String elValue = el.getStringValue(); // 如果为空的话，老是返回 "null"
            if (null == elValue || "".equals(elValue) || "null".equals(elValue)) {
                return "";
            }
            else {
                return elValue;
            }
        }
        return "";
    }

    /**
     * 获取指定nodeName的值的List,如: <root> <info> <eleA>123</eleA> <eleB>456</eleB> </info> <info> <eleA>789</eleA>
     * <eleB>222</eleB> </info> </root>
     * <p>
     * getElementStringValueList(root, "info", "eleA"); 获取到的List包含["123", "789];
     *
     * @param root
     * @param parentNodeName
     * @param nodeName
     * @return
     */
    public static List getElementStringValueList(Element root, String parentNodeName, String nodeName) {
        List list = new ArrayList();
        Element foo;
        String nv = "";
        for (Iterator iterator = root.elementIterator(parentNodeName); iterator.hasNext();) {
            foo = (Element) iterator.next();
            nv = foo.elementText(nodeName);
            if (nv != null && "null".equalsIgnoreCase(nv)) {
                list.add("");
            }
            else if (nv != null && !"null".equalsIgnoreCase(nv)) {
                list.add(nv);
            }
            else {
                list.add("");
            }
        }
        return list;
    }

    /**
     * 取得xml文件的根节点名称，即消息名称。
     *
     * @param xmlStr xml内容
     * @return String 返回名称
     */
    public static String getRootName(String xmlStr) throws Exception {
        Document doc = parse(xmlStr);
        Element root = doc.getRootElement();
        return root.getName();
    }

    /**
     * 将XML转换为Map，每个节点对应1个Map，子节点作为嵌套Map
     *
     * @param element
     * @param out
     */
    public static void createMap(Element element, Map out) {
        long start = System.currentTimeMillis();
        if (element == null) {
            throw new IllegalArgumentException("element is null");
        }

        if (out == null) {
            throw new IllegalArgumentException("out is null");
        }

        if ((element.elements() == null || element.elements().size() == 0)
            && (element.attributes() == null || element.attributes().size() == 0)) { // 不带属性叶子节点
            put(out, element.getName(), (element.getStringValue() != null) ? element.getStringValue().trim() : "");

        }
        else { // 非叶子节点 带属性叶子节点
            HashMap m = new HashMap();
            // 处理节点属性
            putAttribute(m, element);

            if (element.elements() != null) {
                for (Iterator i = element.elements().iterator(); i.hasNext();) {
                    createMap((Element) i.next(), m);
                }
            }

            put(out, element.getName(), m);
        }
        long end = System.currentTimeMillis();
        // log.debug("createMap cost:"+(end-start)+"ms");
    }

    private static void putAttribute(Map m, Element e) {
        if (e.attributes().size() > 0) {
            Iterator it_attr = e.attributes().iterator();
            while (it_attr.hasNext()) {
                Attribute attribute = (Attribute) it_attr.next();
                String attrname = attribute.getName();
                String attrvalue = attribute.getValue();
                m.put(attrname, attrvalue);
            }
        }
    }

    private static void put(Map m, Object key, Object value) {
        Object o = m.get(key);

        if (o == null) {
            m.put(key, value);

            return;
        }

        if (o instanceof List) {
            ((List) o).add(value);

            return;
        }

        ArrayList l = new ArrayList();
        l.add(o);
        l.add(value);
        m.put(key, l);
    }

    /**
     * 把xml文件转换为map形式，其中key为有值的节点名称，并以其所有的祖先节点为前缀，用 "."相连接。如：SubscribeServiceReq.Send_Address.Address_Info.DeviceType
     *
     * @param xmlStr xml内容
     * @return Map 转换为map返回
     * @throws DocumentException
     */
    public static Map<String, String> xml2Map(String xmlStr) throws IOException, DocumentException {
        Map<String, String> rtnMap = new HashMap<String, String>();
        Document doc = parse(xmlStr);
        // 得到根节点
        Element root = doc.getRootElement();
        String rootName = root.getName();
        rtnMap.put("root.name", rootName);

        // 调用递归函数，得到所有最底层元素的名称和值，加入map中
        convert(root, rtnMap, rootName);

        return rtnMap;
    }

    /**
     * 递归函数，找出最下层的节点并加入到map中，由xml2Map方法调用。
     *
     * @param e xml节点，包括根节点
     * @param map 目标map
     * @param lastname 从根节点到上一级节点名称连接的字串
     */
    public static void convert(Element e, Map<String, String> map, String lastname) {
        if (e.attributes().size() > 0) {
            Iterator it_attr = e.attributes().iterator();
            while (it_attr.hasNext()) {
                Attribute attribute = (Attribute) it_attr.next();
                String attrname = attribute.getName();
                String attrvalue = attribute.getValue();
                map.put(lastname + "." + attrname, attrvalue);
            }
        }
        List children = e.elements();
        Iterator it = children.iterator();
        while (it.hasNext()) {
            Element child = (Element) it.next();
            String name = lastname + "." + child.getName();
            // 如果有子节点，则递归调用
            if (child.elements().size() > 0) {
                convert(child, map, name);
            }
            else {
                // 如果没有子节点，则把值加入map
                map.put(name, child.getText());
                // 如果该节点有属性，则把所有的属性值也加入map
                if (child.attributes().size() > 0) {
                    Iterator attr = child.attributes().iterator();
                    while (attr.hasNext()) {
                        Attribute attribute = (Attribute) attr.next();
                        String attrname = attribute.getName();
                        String attrvalue = attribute.getValue();
                        map.put(name + "." + attrname, attrvalue);
                    }
                }
            }
        }
    }

    /**
     * 打印map 的所有key和value
     *
     * @param map
     */
    public static void printMap(Map<String, String> map) {
        Iterator<String> keys = map.keySet().iterator();
        while (keys.hasNext()) {
            String key = keys.next();
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

    }

    public static void createMap(Element element, Map out, Element docMaper) {
        String mapperXml = docMaper.asXML();
        if (element.elements() == null || element.elements().size() == 0) {
            put(out, element.getName(), (element.getStringValue() != null) ? element.getStringValue().trim() : "");
        }
        else {
            HashMap m = null;
            for (Iterator i = element.elements().iterator(); i.hasNext();) {
                createMap((Element) i.next(), m, docMaper);
            }
            // put(out, element.getName(), m);
            Element xpathElement = getMaperElment(docMaper, element.getPath());
            if (xpathElement != null) {
                String elementName = xpathElement.attributeValue("fieldName");
                elementName = (elementName == null || "".equals(elementName)) ? (element.getName()) : elementName;
                List list = (List) out.get(elementName);
                if (list == null) {
                    list = new ArrayList();
                    out.put(elementName, list);
                }
                list.add(m);

            }
            else {
                out.put(element.getName(), m);
            }
        }
    }

    private static Element getMaperElment(Element docMaper, String path) {
        if (docMaper.elements().size() > 0) {
            for (Iterator i = docMaper.elements().iterator(); i.hasNext();) {
                Element item = (Element) i.next();
                if (path.equals(item.attributeValue("xpath"))) {
                    return item;
                }
            }
        }
        return null;
    }

    /**
     * xml parse to map
     * 
     * @param map
     * @param xml
     */
    public static void parseXmlToMap(Map out, String xml) throws Exception {
        Document doc = parse(xml);
        Element root = doc.getRootElement();
        createMap(root, out);
    }

}
